package xyz_test

import (
	"math"
	"reflect"
	"testing"

	"github.com/twpayne/go-geom"
	"github.com/twpayne/go-geom/xyz"
)

func TestVectorDot(t *testing.T) {
	for i, tc := range []struct {
		v1, v2, v3, v4 geom.Coord
		result         float64
	}{
		{
			v1:     geom.Coord{0.44022007739138613, 0.833525569726002, 0.49302724302422873},
			v2:     geom.Coord{0.05162589254031058, 0.977176382882891, 0.8789402270478548},
			v3:     geom.Coord{0.7534455876162328, 0.6173555367190986, 0.27126435983727104},
			v4:     geom.Coord{0.8452219342333697, 0.5825792503932398, 0.4764854482064663},
			result: 0.038538086185549936,
		},
		{
			v1:     geom.Coord{0.20955744747823457, 0.5172686316103566, 0.6801997230482258},
			v2:     geom.Coord{0.5189545122370025, 0.7138294585693206, 0.1703904366365746},
			v3:     geom.Coord{0.1299667150322601, 0.42936729516932814, 0.39447696995105985},
			v4:     geom.Coord{0.210552526485147, 0.08442740855375197, 0.14719730521711372},
			result: 0.08319681358256323,
		},
		{
			v1:     geom.Coord{0.42923106228931585, 0.8789539905529137, 0.9049839556871452},
			v2:     geom.Coord{0.8179157436095014, 0.7590965973803714, 0.3675305177597894},
			v3:     geom.Coord{0.41420869787405223, 0.15048205340073806, 0.2379018154739312},
			v4:     geom.Coord{0.3062271094133202, 0.9149564562570988, 0.2890144389739814},
			result: -0.1610693535943949,
		},
		{
			v1:     geom.Coord{0.0720367621447221, 0.6033943848353848, 0.28404356439509015},
			v2:     geom.Coord{0.40509222469259154, 0.7434042304355827, 0.04742003850930543},
			v3:     geom.Coord{0.7578339439559231, 0.22202382516160535, 0.6213020508504824},
			v4:     geom.Coord{0.9107151373683526, 0.9928925052966305, 0.5935476692418898},
			result: 0.165414461105585,
		},
		{
			v1:     geom.Coord{0.6379012306377657, 0.0364320825224973, 0.6069364718946939},
			v2:     geom.Coord{0.07681594329836916, 0.7271795021838152, 0.5337993618776601},
			v3:     geom.Coord{0.6836358505889734, 0.16314352434181822, 0.2086152270084457},
			v4:     geom.Coord{0.25971610921754373, 0.6593843789584228, 0.45988798892115257},
			result: 0.5622548561208845,
		},
	} {
		dot := xyz.VectorDot(tc.v1, tc.v2, tc.v3, tc.v4)

		if math.Abs(dot-tc.result) > 1e-16 {
			t.Errorf("Test %v failed: expected %v but was %v", i+1, tc.result, dot)
		}
	}
}

func TestVectorLength(t *testing.T) {
	for i, tc := range []struct {
		v1     geom.Coord
		result float64
	}{
		{
			v1:     geom.Coord{0.050809870984833916, 0.31035561291492797, 0.001499306503938036},
			result: 0.3144908542029304,
		},
		{
			v1:     geom.Coord{0.3778623754360245, 0.5961241142000473, 0.1543705256123552},
			result: 0.7224778152156514,
		},
		{
			v1:     geom.Coord{0.17262019190470224, 0.8427909969516906, 0.7320393785809436},
			result: 1.1295910972512198,
		},
		{
			v1:     geom.Coord{0.9902618503498587, 0.7797449095443413, 0.6700506102217009},
			result: 1.4274412339837714,
		},
		{
			v1:     geom.Coord{0.7261126271829389, 0.5908928510465574, 0.49826419025381485},
			result: 1.0605004064410954,
		},
	} {
		length := xyz.VectorLength(tc.v1)

		if math.Abs(length-tc.result) > 1e-15 {
			t.Errorf("Test %v failed: expected %v but was %v", i+1, tc.result, length)
		}
	}
}

func TestVectorNormalize(t *testing.T) {
	for i, tc := range []struct {
		v1     geom.Coord
		result geom.Coord
	}{
		{
			v1:     geom.Coord{0.9807055460429551, 0.8643056316322373, 0.08720913878428183},
			result: geom.Coord{0.7485619198694545, 0.6597151260937918, 0.06656579094706616},
		},
		{
			v1:     geom.Coord{0.19711119037615354, 0.022309298847895676, 0.39090961970304994},
			result: geom.Coord{0.449654368739906, 0.05089246161690294, 0.8917515943488349},
		},
		{
			v1:     geom.Coord{0.9127793841967227, 0.6724248357179903, 0.040467674312273494},
			result: geom.Coord{0.8046063719236741, 0.5927361165530226, 0.03567187117973928},
		},
		{
			v1:     geom.Coord{0.953437460047214, 0.4056862296158039, 0.7368918558390393},
			result: geom.Coord{0.7498706721738382, 0.3190688623442679, 0.5795593464830763},
		},
		{
			v1:     geom.Coord{0.3364349123702868, 0.267116248617841, 0.5027935537217091},
			result: geom.Coord{0.5087342893100769, 0.4039152594074621, 0.7602906589574631},
		},
	} {
		normalized := xyz.VectorNormalize(tc.v1)

		if !reflect.DeepEqual(normalized, tc.result) {
			t.Errorf("Test %v failed: expected %v but was %v", i+1, tc.result, normalized)
		}
	}
}
